package optimizers.ganeat.jankenpon.report;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Properties;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.swing.JFileChooser;

import model.Input;
import model.OligoSystemGeneral;
import model.OligoSystemSimple;

import fitness.JankenponResult;

import optimizers.ganeat.Constants;
import optimizers.ganeat.Individual;
import optimizers.ganeat.Species;
import optimizers.ganeat.jankenpon.ConstantsJankenpon;
import optimizers.ganeat.jankenpon.JankenponIndividual;
import optimizers.ganeat.jankenpon.JankenponMatch;
import optimizers.ganeat.jankenpon.JankenponMatchResult;
import optimizers.ganeat.report.ReaderNEAT;
import util.JankenponEventHandler;
import visualization.PlotExpData;

public class JankenponReader extends ReaderNEAT {
	
	public static void competeSinceForever(File file){
		FileInputStream saveFile = null;	
			try {
				saveFile = new FileInputStream(file);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ObjectInputStream restore = null;
			try {
				restore = new ObjectInputStream(saveFile);
				ArrayList<ArrayList<Species>> speciesVisualData = (ArrayList<ArrayList<Species>>) restore
				.readObject();
				
				Properties properties = new Properties();
				
				try{
					try {
					 java.io.FileInputStream fis = new java.io.FileInputStream("run.properties");
					properties.load(fis);
			         fis.close();
					} catch (FileNotFoundException e) {
						System.out.println("No properties found. Creating file");
						PrintWriter prop = new PrintWriter("run.properties");
						prop.print("threads = "+Runtime.getRuntime().availableProcessors());
						prop.flush();
						prop.close();
						properties.put("threads", ""+Runtime.getRuntime().availableProcessors());
					} 
				}catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		         
				
				if(!properties.containsKey("threads")){
					properties.put("threads", ""+Runtime.getRuntime().availableProcessors());
				}
				
				int nbOfThreads = Integer.parseInt((String) properties.getProperty("threads"));
				
				ArrayList<JankenponIndividual> allStars = new ArrayList<JankenponIndividual>();
				//Free-for-all massive brawl.
				
				for(int i=0;i<speciesVisualData.size();i++){

					Individual bestIndividual = null;

					for(Species sp : speciesVisualData.get(i)){
						if (bestIndividual == null
								|| bestIndividual.getFitness() < sp
										.getBestIndividual().getFitness()) {
							bestIndividual = sp.getBestIndividual();
							
						}
					}
					bestIndividual.fitnessResult = new JankenponResult();
					allStars.add(((JankenponIndividual) bestIndividual).clone());
				}
				
				ArrayList<Future<Object>> futures = new ArrayList<Future<Object>>();
				CompletionService<Object> cservice;
				ExecutorService eservice = Executors.newFixedThreadPool(nbOfThreads);
				cservice = new ExecutorCompletionService<Object>(eservice);
				int taskCount=0;

					for(int i=0; i < allStars.size()-1; i++){
						for(int j=i+1; j<allStars.size(); j++){
							futures.add(cservice
									.submit(new JankenponMatch(allStars.get(i),allStars.get(j))));
								taskCount++;
							}
						}
					

				int numberOfMatches = 0;
				for (int i = 0; i < taskCount; i++) {
					try {
						//System.out.println(this.maxRunTime);
						Future<Object> future = cservice.poll(100, TimeUnit.SECONDS);
						if (future != null) {
							JankenponMatchResult result = (JankenponMatchResult) future
									.get();
							
							if(result.winner == null){
								System.err.println("Possible future interupt");
							}
							//int index = Arrays.asList(nextGen).indexOf(result.winner);
							System.out.println(numberOfMatches + ":Indiv " + result.winner.individualIndex
									+ "(Fitness "
									+ result.winner.getFitnessString()
									+ ")"
									+ result.winner.printSimpleModel()
									+ " against "
									+ (result.loser==null?"nobody":result.loser.printSimpleModel()));
							JankenponMatch.updatePlayers(result);
							numberOfMatches++;
						} else {
							//for (Future<Object> future1 : futures) {
							//	if (future1 != null) {
							//		future1.cancel(true);
							//	}
							//}
							//logger.logToMemory(i + ": Drop");
							//break;
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				double[] averageOverGeneration = new double[allStars.size()];
				double value;
				String st = "";
				for(int i=0; i<allStars.size(); i++){
					
						value = allStars.get(i).fitnessResult.finalResult();
					
					averageOverGeneration[i] = value;
					st+= value + "\n";
				}
				FileOutputStream savinFile = new FileOutputStream("JankenponAposterioriFitness"+System.currentTimeMillis());
				ObjectOutputStream save = new ObjectOutputStream(savinFile);
				save.writeObject(st);
				save.close();
				
				PlotExpData demo = new PlotExpData("Fitness over generations", new double[][]{averageOverGeneration}, new String[]{"Average fitness"}, "Generation", "Score");
				demo.setVisible(true);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}

	public static void showMatch(File file, int index1, int index2){
		FileInputStream saveFile = null;	
		try {
			saveFile = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ObjectInputStream restore = null;
		try {
			restore = new ObjectInputStream(saveFile);
			ArrayList<ArrayList<Species>> speciesVisualData = (ArrayList<ArrayList<Species>>) restore
			.readObject();
			JankenponIndividual indiv1,indiv2;
			indiv1 = null;
			indiv2 = null;
			for(Species sp : speciesVisualData.get(index1)){
				if (indiv1 == null
						|| indiv1.getFitness() < sp
								.getBestIndividual().getFitness()) {
					indiv1 = (JankenponIndividual) sp.getBestIndividual();
					
				}
			}
			for(Species sp : speciesVisualData.get(index2)){
				if (indiv2 == null
						|| indiv2.getFitness() < sp
								.getBestIndividual().getFitness()) {
					indiv2 = (JankenponIndividual) sp.getBestIndividual();
					
				}
			}
			Individual match = indiv1.createMatch(indiv2);
			OligoSystemGeneral oligoModel = match.getOligoModel();
			OligoSystemSimple oligo = new OligoSystemSimple(oligoModel.nSimpleSequences, oligoModel.templates, oligoModel.seqK, oligoModel.inhK, oligoModel.seqConcentration, oligoModel.exo.activity);
			
			oligo.inputs = new Input[ConstantsJankenpon.rounds];
			for(int i= 0; i< ConstantsJankenpon.rounds; i++){
				oligo.inputs[i] = new Input(oligoModel.nameToInt.get(ConstantsJankenpon.JUDGESTRING),ConstantsJankenpon.pulse,ConstantsJankenpon.initialTime+i*ConstantsJankenpon.fightTime);
			}
			
			double[][] data = oligo.calculateTimeSeries(new JankenponEventHandler(oligo.inputs));
			String[] seqNames = new String[data.length];
			for (int i = 0; i < data.length; i++) {
				seqNames[i] = oligoModel.intToName.get(i);
				if (seqNames[i] == null)
					seqNames[i] = String.valueOf(i);
			}
			String export = "#";
			String[] importants = new String[]{"A","a","b","c","Ca","Cb","Cc"};
			for(int i=0;i<importants.length;i++){ // number of sequences
				export += importants[i]+"\t";
			}
			export += "\n";
			
			for(int t=0;t<data[0].length;t++){
				for(int i=0;i<importants.length;i++){
					export+= ""+ data[oligoModel.nameToInt.get(importants[i])][t] + "\t";
				}
				export+= "\n";
			}
			JFileChooser exp = new JFileChooser();
			int result = exp.showSaveDialog(null);
			if (result == JFileChooser.APPROVE_OPTION){
				File selectedFile = exp.getSelectedFile();
				try {
					if (!selectedFile.exists()){

						selectedFile.createNewFile();
					
					}
					
					FileWriter fw = new FileWriter(selectedFile);
					fw.write(export);
					fw.flush();
					fw.close();
					
				} catch (IOException e) {
					
					e.printStackTrace();
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws ClassNotFoundException {
		// TODO Auto-generated method stub

		JFileChooser fc = new JFileChooser();
		int returnVal;
		do {
			returnVal = fc.showOpenDialog(null);
		} while (returnVal != JFileChooser.APPROVE_OPTION
				&& returnVal != JFileChooser.CANCEL_OPTION);
		File file = fc.getSelectedFile();
		 //File file = new File(
		 //"/Users/Lab_Member/Documents/workspace/SB_Project/result/NEAT_2013_03_19 16_59_49_Square");
		System.out.println(file.toString());
		competeSinceForever(file);
		//showMatch(file,180,50);
	}
	
}
